﻿/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * Author: Laurent WOUTERS
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Hime.Redist.Parsers;

namespace xowl.gmi.compiler.transform
{
    class TransformationRule
    {
        public const string Deprecated = "deprecated";
        private const string vars = "abcdefghijklmnopqrstuvwxyz";

        private int nextIndex;
        private List<Pattern> left;
        private List<Pattern> right;
        private string name;
        private string direction;
        private List<string> annotations;

        public string Name { get { return name; } }
        public string Direction { get { return direction; } }
        public void AddAnnotation(string annotation)
        {
            if (annotation != null && annotation != string.Empty)
                annotations.Add(annotation);
        }
        public bool IsAnnotated(string annotation) { return annotations.Contains(annotation); }

        public string GetNextVar()
        {
            string var = vars[nextIndex].ToString();
            nextIndex++;
            return var;
        }

        public TransformationRule(string name, string direction)
        {
            this.nextIndex = 0;
            this.name = name;
            this.left = new List<Pattern>();
            this.right = new List<Pattern>();
            this.direction = direction;
            this.annotations = new List<string>();
        }

        public TransformationRule(SyntaxTreeNode node)
        {
            this.nextIndex = 0;
            this.name = (node.Children[2].Symbol as SymbolTokenText).ValueText;
            this.left = new List<Pattern>();
            this.right = new List<Pattern>();
            this.direction = (node.Children[1].Symbol as SymbolTokenText).ValueText;
            this.annotations = new List<string>();
            Context context = new Context();
            foreach (SyntaxTreeNode child in node.Children[3].Children)
                this.left.Add(LoadPattern(context, child));
            foreach (SyntaxTreeNode child in node.Children[4].Children)
                this.right.Add(LoadPattern(context, child));
            foreach (SyntaxTreeNode child in node.Children[0].Children)
                this.annotations.Add(LoadAnnotation(child));
        }

        private string LoadAnnotation(SyntaxTreeNode ast)
        {
            string value = (ast.Symbol as SymbolTokenText).ValueText;
            if (value.Length == 3)
                return string.Empty;
            return value.Substring(3).Trim();
        }

        private Pattern LoadPattern(Context context, SyntaxTreeNode ast)
        {
            bool isMeta = (ast.Children[0].Children.Count != 0);
            bool isNegative = (ast.Children[1].Children.Count != 0);
            if (ast.Children[2].Symbol.Name == "pattern_ast")
                return new PatternAST(context, ast.Children[2]);
            string name = (ast.Children[2].Children[0].Symbol as SymbolTokenText).ValueText;
            if (name[0] >= 'a' && name[0] <= 'z')
                return new PatternBuiltin(context, ast.Children[2], isMeta, isNegative);
            return new PatternOWL(context, ast.Children[2], isMeta, isNegative);
        }

        internal static PatternPart GetPatternPart(Context context, SyntaxTreeNode ast)
        {
            if (ast.Symbol.Name == "VARIABLE")
                return context.Resolve(((SymbolTokenText)ast.Symbol).ValueText);
            return new Constant(ast);
        }

        public void AddOnLeft(Pattern pattern) { left.Add(pattern); }
        public void AddOnRight(Pattern pattern) { right.Add(pattern); }

        public void Write(StreamWriter writer)
        {
            if (annotations.Count != 0)
            {
                writer.WriteLine("///");
                foreach (string annotation in annotations)
                    writer.WriteLine("/// " + annotation);
                writer.WriteLine("///");
            }
            writer.WriteLine("\trule " + direction + " " + name + " {");
            foreach (Pattern pattern in left)
            {
                writer.Write("\t\t");
                pattern.Write(writer);
                writer.WriteLine();
            }
            writer.WriteLine("\t} => {");
            foreach (Pattern pattern in right)
            {
                writer.Write("\t\t");
                pattern.Write(writer);
                writer.WriteLine();
            }
            writer.WriteLine("\t}");
        }

        public void WriteOWL(StreamWriter writer)
        {
            writer.WriteLine("\tRule(:" + name);
            writer.WriteLine("\t\tAntecedents(");
            foreach (Pattern pattern in left)
            {
                writer.Write("\t\t\t");
                pattern.WriteOWL(writer);
                writer.WriteLine();
            }
            writer.WriteLine("\t\t)");
            writer.WriteLine("\t\tConsequents(");
            foreach (Pattern pattern in right)
            {
                writer.Write("\t\t\t");
                pattern.WriteOWL(writer);
                writer.WriteLine();
            }
            writer.WriteLine("\t\t)");
            writer.WriteLine("\t)");
        }
    }
}
